5.3 Daten filtern und gruppieren#

Im vorherigen Kapitel haben wir Autos basierend auf ihrem Kilometerstand gruppiert und visualisiert. Während diese Gruppierung automatisch im Hintergrund stattfand, werden wir in diesem Kapitel lernen, wie wir direkt auf die gruppierten Daten zugreifen und zusätzliche Analysen durchführen können.

Lernziele#

Lernziele

  • Sie wissen, dass die Wahrheitswerte True (wahr) oder False (falsch) in dem Datentyp bool gespeichert werden.

  • Sie kennen die wichtigsten Vergleichsoperatoren (<, <=, >, >=, ==, !=, in, not in) in Python.

  • Sie können ein Pandas-DataFrame-Objekt nach einem Wert filtern.

  • Sie können ein Pandas-DataFrame-Objekt mit den Methoden groupby() und get_group() gruppieren.

Daten filtern#

Im vorherigen Kapitel haben wir die Kilometerstände von Autos untersucht, die im Jahr 2020 zugelassen und Mitte 2023 auf Autoscout24.de angeboten wurden. Bei der Kategorisierung der Kilometerstände fiel auf, dass Fahrzeuge mit einer Laufleistung von über 200000 km selten sind. Trotzdem beeinflusste dies die Aufteilung in zehn gleichmäßige Gruppen, die von 0 km bis 435909 km reichten, erheblich. Um eine genauere Analyse zu ermöglichen, wäre es sinnvoll, Fahrzeuge mit einer Laufleistung von bis zu 200.000 km in den Fokus zu nehmen und die Ausreißer auszuschließen. Daher widmen wir uns in diesem Kapitel der Filterung von tabellarischen Datensätzen mithilfe von Pandas.

Zuerst laden wir den Datensatz autoscout24_DE_2020.csv und überprüfen den Inhalt.

import pandas as pd

url = 'https://gramschs.github.io/book_ml4ing/data/autoscout24_DE_2020.csv'
data = pd.read_csv(url)
data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 18566 entries, 0 to 18565
Data columns (total 14 columns):
 #   Column                Non-Null Count  Dtype  
---  ------                --------------  -----  
 0   Marke                 18566 non-null  object 
 1   Modell                18566 non-null  object 
 2   Farbe                 18546 non-null  object 
 3   Erstzulassung         18566 non-null  object 
 4   Jahr                  18566 non-null  int64  
 5   Preis (Euro)          18566 non-null  int64  
 6   Leistung (kW)         18552 non-null  float64
 7   Leistung (PS)         18552 non-null  float64
 8   Getriebe              18566 non-null  object 
 9   Kraftstoff            18566 non-null  object 
 10  Verbrauch (l/100 km)  15501 non-null  object 
 11  Verbrauch (g/km)      18566 non-null  object 
 12  Kilometerstand (km)   18566 non-null  float64
 13  Bemerkungen           18566 non-null  object 
dtypes: float64(3), int64(2), object(9)
memory usage: 2.0+ MB

Um die Autos mit einem Kilometerstand von bis zu 200000 km zu filtern, vergleichen wir die entsprechende Spalte mit dem Wert 200000, indem wir den aus der Mathematik bekannten Kleiner-gleich-Operator <= benutzen. Das Ergebnis dieses Vergleichs speichern wir in der Variable bedingung_kilometerstand.

bedingung_kilometerstand = data['Kilometerstand (km)'] <= 200000

Aber was genau ist in der Variable bedingung_kilometerstand enthalten? Schauen wir uns den Datentyp an:

type(bedingung_kilometerstand)
pandas.core.series.Series

Offensichtlich handelt es sich um ein Pandas-Series-Objekt. Für weitere Informationen können wir die .info()-Methode aufrufen:

bedingung_kilometerstand.info()
<class 'pandas.core.series.Series'>
RangeIndex: 18566 entries, 0 to 18565
Series name: Kilometerstand (km)
Non-Null Count  Dtype
--------------  -----
18566 non-null  bool 
dtypes: bool(1)
memory usage: 18.3 KB

In dem Series-Objekt sind 18566 Einträge vom Datentyp bool gespeichert. Diesen Datentyp haben wir bisher nicht kennengelernt. Wir lassen die ersten fünf Einträge ausgeben:

bedingung_kilometerstand.head()
0    True
1    True
2    True
3    True
4    True
Name: Kilometerstand (km), dtype: bool

Sind alle Einträge mit dem Wert True gefüllt? Wie viele und vor allem welche einzigartige Einträge gibt es in diesem Series-Objekt?

bedingung_kilometerstand.unique()
array([ True, False])

Das Series-Objekt enthält nur True und False, was den Datentyp bool charakterisiert. In diesem Datentyp können nur zwei verschiedene Werte gespeichert werden, nämlich wahr (True) und falsch (False). Oft sind Wahrheitswerte das Ergebnis eines Vergleichs, wie das folgende Code-Beispiel zeigt:

x = 19
print(x < 100)
True

In der Python-Programmierung wird der Datentyp bool oft verwendet, um Programmcode zu verzweigen. Damit ist gemeint, dass Teile des Programms nur durchlaufen und ausgeführt werden, wenn eine bestimmte Bedingung wahr (True) ist. In dieser Vorlesung benutzen wir bool-Werte hauptsächlich zum Filtern von Daten.

Welche Vergleichsoperatoren kennt Python?

In Python können die mathematischen Vergleichsoperatoren in ihrer gewohnten Schreibweise verwendet werden:

  • < kleiner als

  • <= kleiner als oder gleich

  • > größer als

  • >= größer als oder gleich

  • == gleich (= ist der Zuweisungsoperator, nicht mit Gleichheit verwechseln!)

  • != ungleich

Darüber hinaus kann mit in oder not in getestet werden, ob ein Element in einer Liste ist oder eben nicht.

Aber was machen wir jetzt mit diesem Series-Objekt? Wir können es als Index benutzen für den ursprünglichen Datensatz benutzen. Die Zeilen, in denen True steht, werden übernommen, die anderen verworfen.

autos_bis_200000km = data[bedingung_kilometerstand]
autos_bis_200000km.info()
<class 'pandas.core.frame.DataFrame'>
Index: 18525 entries, 0 to 18565
Data columns (total 14 columns):
 #   Column                Non-Null Count  Dtype  
---  ------                --------------  -----  
 0   Marke                 18525 non-null  object 
 1   Modell                18525 non-null  object 
 2   Farbe                 18505 non-null  object 
 3   Erstzulassung         18525 non-null  object 
 4   Jahr                  18525 non-null  int64  
 5   Preis (Euro)          18525 non-null  int64  
 6   Leistung (kW)         18511 non-null  float64
 7   Leistung (PS)         18511 non-null  float64
 8   Getriebe              18525 non-null  object 
 9   Kraftstoff            18525 non-null  object 
 10  Verbrauch (l/100 km)  15472 non-null  object 
 11  Verbrauch (g/km)      18525 non-null  object 
 12  Kilometerstand (km)   18525 non-null  float64
 13  Bemerkungen           18525 non-null  object 
dtypes: float64(3), int64(2), object(9)
memory usage: 2.1+ MB

Von den 18566 Autos wurden 18525 Autos übernommen. Ist denn die Filterung geglückt? Wir verschaffen uns mit der .describe()-Methode einen schnellen Überblick.

autos_bis_200000km.describe()
Jahr Preis (Euro) Leistung (kW) Leistung (PS) Kilometerstand (km)
count 18525.0 18525.000000 18511.000000 18511.000000 18525.000000
mean 2020.0 33513.975816 135.327697 184.079466 42251.647935
std 0.0 37458.475775 75.548942 102.680858 28741.442712
min 2020.0 5950.000000 4.000000 5.000000 0.000000
25% 2020.0 19990.000000 90.000000 122.000000 22720.000000
50% 2020.0 26489.000000 110.000000 150.000000 35722.000000
75% 2020.0 35490.000000 148.000000 201.000000 54422.000000
max 2020.0 959980.000000 596.000000 810.000000 199000.000000

Der maximale Eintrag für die Spalte Kilometerstand (km) ist 199000 km. Mit dem Tilde-Operator ~ können wir das Pandas-Series-Objekt bedingung_kilometerstand in das Gegenteil umwandeln. Damit können wir also die Autos mit einem Kilometerstand über 200.000 km herausfiltern.

autos_ab_200000km = data[~bedingung_kilometerstand]
autos_ab_200000km.info()
<class 'pandas.core.frame.DataFrame'>
Index: 41 entries, 968 to 18517
Data columns (total 14 columns):
 #   Column                Non-Null Count  Dtype  
---  ------                --------------  -----  
 0   Marke                 41 non-null     object 
 1   Modell                41 non-null     object 
 2   Farbe                 41 non-null     object 
 3   Erstzulassung         41 non-null     object 
 4   Jahr                  41 non-null     int64  
 5   Preis (Euro)          41 non-null     int64  
 6   Leistung (kW)         41 non-null     float64
 7   Leistung (PS)         41 non-null     float64
 8   Getriebe              41 non-null     object 
 9   Kraftstoff            41 non-null     object 
 10  Verbrauch (l/100 km)  29 non-null     object 
 11  Verbrauch (g/km)      41 non-null     object 
 12  Kilometerstand (km)   41 non-null     float64
 13  Bemerkungen           41 non-null     object 
dtypes: float64(3), int64(2), object(9)
memory usage: 4.8+ KB

41 Autos, die 2020 zugelassen wurden, sollten Mitte 2023 mit einem Kilometerstand von mehr als 200000 km verkauft werden. Schauen wir uns die Statistik an.

autos_ab_200000km.describe()
Jahr Preis (Euro) Leistung (kW) Leistung (PS) Kilometerstand (km)
count 41.0 41.000000 41.000000 41.000000 41.000000
mean 2020.0 20958.926829 115.463415 156.975610 245033.951220
std 0.0 8955.785235 40.915216 55.554247 53031.305157
min 2020.0 8000.000000 56.000000 76.000000 201000.000000
25% 2020.0 15740.000000 85.000000 116.000000 209800.000000
50% 2020.0 19950.000000 103.000000 140.000000 227846.000000
75% 2020.0 26000.000000 140.000000 190.000000 259000.000000
max 2020.0 44900.000000 255.000000 347.000000 435909.000000

Und was sind das für Autos?

autos_ab_200000km.head(10)
Marke Modell Farbe Erstzulassung Jahr Preis (Euro) Leistung (kW) Leistung (PS) Getriebe Kraftstoff Verbrauch (l/100 km) Verbrauch (g/km) Kilometerstand (km) Bemerkungen
968 audi Audi A6 silber 05/2020 2020 29100 170.0 231.0 Automatik Hybrid (Elektro/Diesel) 5,9 l/100 km 187 g/km 215000.0 Avant 45 TDI quattro sport
1136 audi Audi S4 weiß 08/2020 2020 34990 255.0 347.0 Automatik Diesel 6,3 l/100 km 165 g/km 227846.0 Avant 3.0 TDI quattro Optik-Paket
2265 bmw BMW 530 weiß 05/2020 2020 32999 195.0 265.0 Automatik Diesel 5,9 l/100 km 156 g/km 209800.0 Baureihe 5 Touring 530 d xDrive M Sport
2340 bmw BMW 218 orange 08/2020 2020 27500 100.0 136.0 Schaltgetriebe Benzin 6 l/100 km - (g/km) 290000.0 218i Coupe M Sport
2726 citroen Citroen Jumper weiß 06/2020 2020 17999 103.0 140.0 Schaltgetriebe Diesel NaN - (g/km) 273999.0 L3 H4#Hoch/Lang#AT Motor erst 100.000km#
2732 citroen Citroen Jumper weiß 09/2020 2020 19975 103.0 140.0 Schaltgetriebe Diesel 6,5 l/100 km 170 g/km 215000.0 35 L4H2 Club Heavy BlueHD (AT Motor/Getr)
2734 citroen Citroen Berlingo weiß 09/2020 2020 11781 56.0 76.0 Schaltgetriebe Diesel 4,1 l/100 km 109 g/km 204377.0 Kasten 1,5 BlueHDI Club M/L1 Klima Pdc
2736 citroen Citroen Berlingo weiß 03/2020 2020 10980 75.0 102.0 Schaltgetriebe Diesel 4 l/100 km 106 g/km 236400.0 Kasten BlueHDi 100 Club M/L1 Kühlkasten
2942 dacia Dacia Dokker grau 02/2020 2020 9500 70.0 95.0 Schaltgetriebe Diesel 4,2 l/100 km 111 g/km 237420.0 Express Comfort/1Hd./Scheckheftgepflegt
3045 dacia Dacia Logan silber 03/2020 2020 9600 70.0 95.0 Schaltgetriebe Diesel 3,6 l/100 km 92 g/km 217400.0 MCV II Kombi Comfort Navi Standh. PDC 8-fach b...

Mini-Übung

Filtern Sie den Datensatz so, dass nur Autos mit einem Preis zwischen 10.000 und 30.000 Euro übrig bleiben. Wie viele Autos erfüllen diese Bedingung? Tipp: Sie können zwei Bedingungen mit & (und) verknüpfen.

Lösung

bedingung_preis = (data['Preis (Euro)'] >= 10000) & (data['Preis (Euro)'] <= 30000)
autos_mittlerer_preis = data[bedingung_preis]
print(f"Anzahl Autos: {len(autos_mittlerer_preis)}")

Es gibt 11.793 Autos in dieser Preisklasse.

Wichtig: Die Klammern um die einzelnen Bedingungen sind notwendig!

Daten gruppieren#

Eine Filterung nach Kilometerstand ermöglicht es uns, die Autos in zwei Datensätze zu teilen: Autos mit bis zu 200000 km Laufleistung und jene mit mehr als 200000 km (hierzu kann der Tilde-Operator (~) verwendet werden).

Wenden wir nun diese Technik an, um die Fahrzeuge basierend auf ihrer Marke zu trennen. Ein Beispiel: Um alle “Audi”-Fahrzeuge zu extrahieren, verwenden wir den folgenden Code:

bedingung_audi = data['Marke'] == 'audi'
audis = data[bedingung_audi]
audis.info()
<class 'pandas.core.frame.DataFrame'>
Index: 1190 entries, 104 to 1293
Data columns (total 14 columns):
 #   Column                Non-Null Count  Dtype  
---  ------                --------------  -----  
 0   Marke                 1190 non-null   object 
 1   Modell                1190 non-null   object 
 2   Farbe                 1190 non-null   object 
 3   Erstzulassung         1190 non-null   object 
 4   Jahr                  1190 non-null   int64  
 5   Preis (Euro)          1190 non-null   int64  
 6   Leistung (kW)         1189 non-null   float64
 7   Leistung (PS)         1189 non-null   float64
 8   Getriebe              1190 non-null   object 
 9   Kraftstoff            1190 non-null   object 
 10  Verbrauch (l/100 km)  1010 non-null   object 
 11  Verbrauch (g/km)      1190 non-null   object 
 12  Kilometerstand (km)   1190 non-null   float64
 13  Bemerkungen           1190 non-null   object 
dtypes: float64(3), int64(2), object(9)
memory usage: 139.5+ KB

Diese Bedingung erfüllen 1.190 Autos. Der Gesamtdatensatz enthält jedoch 41 unterschiedliche Automarken. Es wäre ineffizient, für jede Marke eine separate Filterung durchzuführen. Deshalb bietet Pandas die .groupby()-Methode, die es erlaubt, die Daten automatisch nach den einzigartigen Einträgen einer Spalte zu gruppieren:

autos_nach_marke = data.groupby('Marke')
type(autos_nach_marke)
pandas.core.groupby.generic.DataFrameGroupBy

Das Resultat ist eine spezielle Pandas-Datenstruktur namens DataFrameGroupBy. Auf dieses Objekt sind nicht alle bekannten DataFrame-Methoden anwendbar, aber beispielsweise die .describe()-Methode darf verwendet werden:

autos_nach_marke.describe()
Jahr Preis (Euro) ... Leistung (PS) Kilometerstand (km)
count mean std min 25% 50% 75% max count mean ... 75% max count mean std min 25% 50% 75% max
Marke
alfa-romeo 88.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 88.0 40263.840909 ... 280.00 510.0 88.0 40671.568182 24303.271950 1000.0 23475.00 36950.0 49743.75 121800.0
aston-martin 16.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 16.0 174516.750000 ... 551.00 725.0 16.0 18923.250000 10374.581569 25.0 10965.00 19200.0 23942.00 42000.0
audi 1190.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 1190.0 42584.115126 ... 310.00 810.0 1190.0 50733.891597 32154.868792 23.0 28500.00 42811.0 65000.00 227846.0
bentley 41.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 41.0 239720.682927 ... 635.00 635.0 41.0 29706.804878 20568.477634 20.0 13500.00 26900.0 39900.00 93600.0
bmw 1039.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 1039.0 38951.122233 ... 265.00 625.0 1039.0 51443.319538 33237.040181 57.0 27675.50 44500.0 67218.00 290000.0
cadillac 1.0 2020.0 NaN 2020.0 2020.0 2020.0 2020.0 2020.0 1.0 74900.000000 ... 426.00 426.0 1.0 51000.000000 NaN 51000.0 51000.00 51000.0 51000.00 51000.0
chevrolet 26.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 26.0 42018.346154 ... 453.00 659.0 26.0 35102.769231 15601.368936 4000.0 21422.25 40258.0 43662.75 65505.0
citroen 446.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 446.0 22244.840807 ... 140.00 299.0 446.0 45375.890135 36573.992887 10.0 22870.00 35000.0 56112.50 273999.0
dacia 268.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 268.0 15726.611940 ... 131.00 150.0 268.0 38283.585821 28492.869299 2729.0 20300.00 33003.5 48292.25 237420.0
dodge 77.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 77.0 52081.272727 ... 401.00 727.0 77.0 47216.012987 26368.755931 6300.0 26959.00 43097.0 64465.00 135200.0
ferrari 54.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 54.0 391129.833333 ... 721.00 799.0 54.0 9954.703704 8160.580428 94.0 4165.25 7325.0 13242.00 33407.0
fiat 493.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 493.0 16630.772819 ... 95.00 178.0 493.0 33325.330629 40859.386352 334.0 14900.00 22966.0 35540.00 399000.0
ford 1632.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 1632.0 27152.117034 ... 190.00 771.0 1632.0 40053.620711 29541.064757 10.0 20895.00 33158.0 50000.00 275000.0
honda 68.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 68.0 27821.191176 ... 184.00 320.0 68.0 32249.588235 18204.167592 6275.0 18337.50 27830.0 44491.75 87150.0
hyundai 431.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 431.0 23627.011601 ... 179.00 275.0 431.0 36495.324826 21943.146134 700.0 21904.00 31850.0 46900.00 142215.0
infiniti 3.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 3.0 30128.333333 ... 258.50 306.0 3.0 47491.666667 39365.402987 20000.0 24944.00 29888.0 61237.50 92587.0
isuzu 3.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 3.0 43564.000000 ... 163.00 163.0 3.0 29081.333333 47560.960475 1622.0 1622.00 1622.0 42811.00 84000.0
jaguar 317.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 317.0 41897.331230 ... 300.00 575.0 317.0 44402.170347 23793.378971 650.0 28890.00 41800.0 57200.00 143444.0
jeep 190.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 190.0 36574.905263 ... 250.00 710.0 190.0 39909.336842 26124.141280 10.0 23000.00 33850.0 53025.00 149429.0
kia 491.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 491.0 24249.158859 ... 200.00 370.0 491.0 42324.835031 25980.689971 4000.0 23695.00 35717.0 54278.50 254228.0
lada 7.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 7.0 15404.857143 ... 102.00 106.0 7.0 18841.714286 9263.874760 35.0 19380.00 20000.0 21048.50 31000.0
lamborghini 50.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 50.0 389851.860000 ... 650.00 770.0 50.0 19970.060000 22682.325994 292.0 4928.75 16977.5 28100.00 143000.0
land-rover 415.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 415.0 53566.137349 ... 300.00 575.0 415.0 47685.327711 25125.806376 0.0 29597.50 42000.0 59900.00 144800.0
maserati 61.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 61.0 89467.704918 ... 460.00 581.0 61.0 33712.180328 30107.363753 50.0 9900.00 24583.0 52534.00 150000.0
mazda 250.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 250.0 25678.544000 ... 184.00 194.0 250.0 36376.016000 23666.670345 1000.0 19726.25 33023.0 46136.75 150000.0
mercedes-benz 1454.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 1454.0 47093.824622 ... 286.00 700.0 1454.0 41981.423659 32327.716743 300.0 21052.50 34584.0 52000.00 435909.0
mini 621.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 621.0 24969.685990 ... 192.00 306.0 621.0 35424.582931 17090.361947 1100.0 22900.00 32850.0 44873.00 98000.0
mitsubishi 105.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 105.0 21177.552381 ... 150.00 224.0 105.0 37161.800000 23745.767214 2800.0 20604.00 30158.0 50857.00 92252.0
nissan 312.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 312.0 25267.009615 ... 159.00 570.0 312.0 40053.500000 22080.302440 2000.0 25000.00 37000.0 49997.75 139870.0
opel 1538.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 1538.0 20929.912874 ... 145.00 300.0 1538.0 38827.157347 26136.851607 15.0 21000.00 32000.0 49830.75 187340.0
peugeot 361.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 361.0 24319.847645 ... 155.00 299.0 361.0 46022.229917 31726.338358 25.0 25000.00 40000.0 59500.00 323190.0
porsche 169.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 169.0 120431.982249 ... 559.25 761.0 169.0 32106.573964 24197.348669 12.0 13774.00 29700.0 45217.00 168000.0
renault 558.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 558.0 20071.415771 ... 150.00 300.0 558.0 41591.388889 35992.337097 20.0 20827.00 32035.0 47050.00 259000.0
rover 2.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 2.0 71770.000000 ... 363.25 404.0 2.0 49350.000000 4242.640687 46350.0 47850.00 49350.0 50850.00 52350.0
seat 1492.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 1492.0 23371.157507 ... 150.00 300.0 1492.0 39579.088472 25351.928571 10.0 23493.25 34186.5 49302.50 234000.0
skoda 1518.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 1518.0 25831.535573 ... 190.00 320.0 1518.0 51537.660079 34791.848676 10.0 27602.00 44688.0 68789.25 282000.0
smart 48.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 48.0 15391.104167 ... 82.00 82.0 48.0 14515.062500 8497.519732 1064.0 8692.75 12050.0 20012.50 36360.0
ssangyong 17.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 17.0 21770.352941 ... 163.00 181.0 17.0 38387.529412 25740.267049 11000.0 22955.00 33119.0 48000.00 107980.0
toyota 783.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 783.0 24200.436782 ... 179.00 381.0 783.0 37311.786718 27091.019478 5.0 19628.00 31489.0 48484.50 255800.0
volkswagen 1359.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 1359.0 28523.032377 ... 199.00 462.0 1359.0 44662.082414 31129.343058 50.0 23986.00 37000.0 56294.50 228336.0
volvo 572.0 2020.0 0.0 2020.0 2020.0 2020.0 2020.0 2020.0 572.0 41352.417832 ... 303.00 408.0 572.0 53661.150350 32460.347772 1246.0 32400.00 47682.0 66307.75 223000.0

41 rows × 40 columns

Für jede Automarke werden nun für jede Spalte mit numerischen Informationen die statistischen Kennzahlen ermittelt. Die entstehende Tabelle ist etwas unübersichtlich. Besser ist daher, sich die statistischen Kennzahlen einzeln ausgeben zu lassen. Im Folgenden ermitteln wir die Mittelwerte der numerischen Informationen nach Automarke. Ohne das Argument numeric_only=True würde Pandas versuchen, auch die nicht-numerischen Spalten (wie ‘Marke’ oder ‘Farbe’) zu mitteln, was zu einer Fehlermeldung führen würde. Mit diesem Argument wird die Operation nur auf numerische Spalten angewendet.

durchschnittspreis_pro_marke = autos_nach_marke['Preis (Euro)'].mean()

# Visualisierung
import plotly.express as px
fig = px.bar(durchschnittspreis_pro_marke, 
             title='Durchschnittlicher Preis pro Automarke',
             labels = {'value': 'Preis [EUR]'})
fig.show()

Eine sehr wichtige Methode der GroupBy-Datenstruktur ist die get_group()-Methode. Damit können wir ein bestimmtes DataFrame-Objekt aus dem GroupBy-Objekt extrahieren:

audis_alternativ = autos_nach_marke.get_group('audi')
audis_alternativ.info()
<class 'pandas.core.frame.DataFrame'>
Index: 1190 entries, 104 to 1293
Data columns (total 14 columns):
 #   Column                Non-Null Count  Dtype  
---  ------                --------------  -----  
 0   Marke                 1190 non-null   object 
 1   Modell                1190 non-null   object 
 2   Farbe                 1190 non-null   object 
 3   Erstzulassung         1190 non-null   object 
 4   Jahr                  1190 non-null   int64  
 5   Preis (Euro)          1190 non-null   int64  
 6   Leistung (kW)         1189 non-null   float64
 7   Leistung (PS)         1189 non-null   float64
 8   Getriebe              1190 non-null   object 
 9   Kraftstoff            1190 non-null   object 
 10  Verbrauch (l/100 km)  1010 non-null   object 
 11  Verbrauch (g/km)      1190 non-null   object 
 12  Kilometerstand (km)   1190 non-null   float64
 13  Bemerkungen           1190 non-null   object 
dtypes: float64(3), int64(2), object(9)
memory usage: 139.5+ KB

In der Variablen audis_alternativ steckt nun der gleiche Datensatz wie in der Variablen audis, den wir bereits durch das Filtern des ursprünglichen Datensatzes extrahiert haben. Beide Methoden führen zum gleichen Ergebnis. Die Filterung mit Bedingungen ist direkter und oft intuitiver. Die Gruppierung mit .groupby() und .get_group() ist besonders nützlich, wenn wir mehrere Gruppen nacheinander untersuchen möchten, da wir die Gruppierung nur einmal durchführen müssen.

Mini-Übung

Gruppieren Sie die Autos nach ‘Kraftstoff’ und berechnen Sie den durchschnittlichen Preis für jede Kraftstoffart. Welche Kraftstoffart ist im Durchschnitt am teuersten?

Lösung

autos_nach_kraftstoff = data.groupby('Kraftstoff')
durchschnittspreis = autos_nach_kraftstoff['Preis (Euro)'].mean()
print(durchschnittspreis.sort_values(ascending=False))

Die teuerste Kraftstoffart im Durchschnitt ist Hybrid (Elektro/Diesel). Einträge ohne Angabe vernachlässigen wir hier.

Wann filtern, wann gruppieren?#

Wir filtern, wenn wir einen Ausschnitt der Daten analysieren wollen. Zum Beispiel könnten wir nur die Audis untersuchen wollen. Das Ergebnis ist ein neuer DataFrame mit den gefilterten Zeilen. Wenn wir jedoch alle Kategorien vergleichen wollen, nutzen wir die Gruppierung. Beispielsweise könnten wir die Durchschnittpreise pro Marke berechnen wollen.

Beide Methoden können auch kombiniert werden. Wir können auch erst gruppieren und dann eine spezifische Gruppe mit .get_group() extrahieren. Dies ist besonders nützlich, wenn wir die Gruppierung für mehrere Analysen wiederverwenden möchten.

Zusammenfassung und Ausblick#

In diesem Kapitel haben wir die Technik des Datenfilterns kennengelernt. Um spezifische Einträge aus einem Datensatz basierend auf einem bestimmten Wert zu extrahieren, nutzen wir Vergleichsoperationen und verwenden das resultierende Series-Objekt als Index. Wenn das Ziel darin besteht, Daten anhand der einzigartigen Werte einer Spalte zu gruppieren, dann ist die Kombination von .groupby() und .get_group() oft der effizienteste Weg. Damit haben wir unsere Einführung in die Datenexploration abgeschlossen, obwohl es noch viele weitere Möglichkeiten gibt, die Daten zu erkunden. Im nächsten Kapitel beginnen wir mit den Grundlagen des maschinellen Lernens und beschäftigen uns mit Entscheidungsbäumen.